import trinity
import util
import log
import paperDoll as pd
import blue
SOURCE_AREA_TYPE_OPAQUE = 0
SOURCE_AREA_TYPE_DECAL = 1
SHADOW_ALPHATEST_EFFECT_PATH = 'res:/Graphics/Effect/Managed/Interior/Avatar/ShadowAlphaTest.fx'
SHADOW_OPAQUE_EFFECT_PATH = 'res:/Graphics/Effect/Managed/Interior/Avatar/Shadow.fx'
SHADOW_CLOTH_ALPHATEST_EFFECT_PATH = 'res:/Graphics/Effect/Managed/Interior/Avatar/ShadowClothAlphaTest.fx'
SHADOW_CLOTH_OPAQUE_EFFECT_PATH = 'res:/Graphics/Effect/Managed/Interior/Avatar/ShadowCloth.fx'
PREPASS_DECAL_EFFECT_PATH = 'res:/Graphics/Effect/Managed/Interior/Avatar/LightPrepassDecal.fx'
PREPASS_OPAQUE_EFFECT_PATH = 'res:/Graphics/Effect/Managed/Interior/Avatar/LightPrepass.fx'
PREPASS_CLOTH_OPAQUE_EFFECT_PATH = 'res:/Graphics/Effect/Managed/Interior/Avatar/LightPrepassCloth.fx'
COLLAPSED_SHADOW_EFFECT_PATH = 'res:/Graphics/Effect/Managed/Interior/Avatar/ShadowCollapsed.fx'

def FindResourceByName(effect, resourceName):
    for res in effect.resources:
        if (res.name == resourceName):
            return res




def FindParameterByName(effect, parameterName):
    for param in effect.parameters:
        if (param.name == parameterName):
            return param




def CopyResource(res):
    if (res is None):
        return 
    else:
        newRes = trinity.TriTexture2DParameter()
        newRes.name = res.name
        newRes.resourcePath = res.resourcePath
        if ((res.resourcePath == '') and (res.resource is not None)):
            newRes.SetResource(res.resource)
        return newRes



def CopyResourceByName(effect, resourceName):
    originalRes = FindResourceByName(effect, resourceName)
    return CopyResource(originalRes)



def CopyVector4Parameter(effect, parameterName):
    newParameter = trinity.Tr2Vector4Parameter()
    newParameter.name = parameterName
    originalParam = FindParameterByName(effect, parameterName)
    if (originalParam is not None):
        newParameter.value = originalParam.value
    else:
        return 
    return newParameter



def CopyFloatParameter(effect, parameterName):
    newParameter = trinity.TriFloatParameter()
    newParameter.name = parameterName
    originalParam = FindParameterByName(effect, parameterName)
    if (originalParam is not None):
        newParameter.value = originalParam.value
    else:
        return 
    return newParameter



def CopyFloatArrayParameter(effect, parameterName):
    newParameter = trinity.TriFloatArrayParameter()
    newParameter.name = parameterName
    originalParam = FindParameterByName(effect, parameterName)
    if (originalParam is not None):
        newParameter.value = originalParam.value
    else:
        return 
    return newParameter



def CopyAreaForPrePassShadows(area, sourceAreaType = SOURCE_AREA_TYPE_OPAQUE):
    originalEffect = area.effect
    if (originalEffect is None):
        return 
    newArea = trinity.Tr2MeshArea()
    newArea.name = area.name
    newArea.index = area.index
    newArea.count = area.count
    newEffect = trinity.Tr2Effect()
    if (area.effect.effectFilePath.lower().find('avatar') == -1):
        if ((sourceAreaType == SOURCE_AREA_TYPE_DECAL) and (area.effect.effectFilePath.lower().find('alphatest') == -1)):
            return 
        elif (area.effect.effectFilePath.lower().find('cloth') == -1):
            if (sourceAreaType == SOURCE_AREA_TYPE_DECAL):
                newEffect.effectFilePath = SHADOW_ALPHATEST_EFFECT_PATH
            else:
                newEffect.effectFilePath = SHADOW_OPAQUE_EFFECT_PATH
        elif (sourceAreaType == SOURCE_AREA_TYPE_DECAL):
            newEffect.effectFilePath = SHADOW_CLOTH_ALPHATEST_EFFECT_PATH
        else:
            newEffect.effectFilePath = SHADOW_CLOTH_OPAQUE_EFFECT_PATH
        newEffect.name = originalEffect.name
        newParam = CopyVector4Parameter(area.effect, 'TransformUV0')
        if (newParam is not None):
            newEffect.parameters.append(newParam)
        if True:
            newParam = CopyVector4Parameter(area.effect, 'MaterialDiffuseColor')
            if (newParam is not None):
                newEffect.parameters.append(newParam)
            newParam = CopyResourceByName(area.effect, 'DiffuseMap')
            if (newParam is not None):
                newEffect.resources.append(newParam)
            newParam = CopyFloatParameter(area.effect, 'CutMaskInfluence')
            if (newParam is not None):
                newEffect.parameters.append(newParam)
            newParam = CopyFloatArrayParameter(area.effect, 'ArrayOfCutMaskInfluence')
            if (newParam is not None):
                newEffect.parameters.append(newParam)
        newArea.effect = newEffect
        return newArea



def CopyAreaForPrePassDepthNormal(area, sourceAreaType = SOURCE_AREA_TYPE_OPAQUE):
    originalEffect = area.effect
    if (originalEffect is None):
        return 
    else:
        if (hasattr(originalEffect, 'effectFilePath') and ('glass' in originalEffect.effectFilePath.lower())):
            return 
        newArea = trinity.Tr2MeshArea()
        newArea.name = area.name
        newArea.index = area.index
        newArea.count = area.count
        newMaterial = trinity.Tr2ShaderMaterial()
        newMaterial.highLevelShaderName = 'NormalDepth'
        if (sourceAreaType == SOURCE_AREA_TYPE_DECAL):
            newMaterial.name = 'Skinned_Cutout_NormalDepth'
            newMaterial.defaultSituation = 'AlphaCutout'
        else:
            newMaterial.name = 'Skinned_Opaque_NormalDepth'
            newMaterial.defaultSituation = ''
        newParam = CopyResourceByName(area.effect, 'NormalMap')
        if (newParam is not None):
            newMaterial.parameters['NormalMap'] = newParam
        newParam = CopyResourceByName(area.effect, 'SpecularMap')
        if (newParam is not None):
            newMaterial.parameters['SpecularMap'] = newParam
        newParam = CopyVector4Parameter(area.effect, 'TransformUV0')
        if (newParam is not None):
            newMaterial.parameters['TransformUV0'] = newParam
        newParam = CopyVector4Parameter(area.effect, 'MaterialSpecularCurve')
        if (newParam is not None):
            newMaterial.parameters['MaterialSpecularCurve'] = newParam
        newParam = CopyVector4Parameter(area.effect, 'MaterialLibraryID')
        if (newParam is None):
            newParam = trinity.Tr2Vector4Parameter()
            newParam.value = (11, 0, 0, 0)
            newParam.name = 'MaterialLibraryID'
        newMaterial.parameters['MaterialLibraryID'] = newParam
        if True:
            newParam = CopyVector4Parameter(area.effect, 'MaterialDiffuseColor')
            if (newParam is not None):
                newMaterial.parameters['MaterialDiffuseColor'] = newParam
            newParam = CopyResourceByName(area.effect, 'DiffuseMap')
            if (newParam is not None):
                newMaterial.parameters['DiffuseMap'] = newParam
            newParam = CopyResourceByName(area.effect, 'CutMaskMap')
            if (newParam is not None):
                newMaterial.parameters['CutMaskMap'] = newParam
            newParam = CopyFloatParameter(area.effect, 'CutMaskInfluence')
            if (newParam is not None):
                newMaterial.parameters['CutMaskInfluence'] = newParam
            newParam = CopyFloatArrayParameter(area.effect, 'ArrayOfCutMaskInfluence')
            if (newParam is not None):
                newMaterial.parameters['ArrayOfCutMaskInfluence'] = newParam
        newArea.effect = newMaterial
        return newArea



def CopyArea(area):
    newArea = area.CloneTo()
    if (newArea.effect is not None):
        if (type(newArea.effect) != trinity.Tr2ShaderMaterial):
            newArea.effect.effectFilePath = area.effect.effectFilePath
            newArea.effect.resources.removeAt(-1)
            for r in area.effect.resources:
                newRes = CopyResource(r)
                if (newRes is not None):
                    newArea.effect.resources.append(newRes)

    return newArea



def CopyAreaForPrePassOpaque(area):
    newArea = CopyArea(area)
    if (newArea.effect is not None):
        p = newArea.effect.effectFilePath.replace('/Exterior/', '/Interior/')
        if not p.endswith('_Prepass.fx'):
            p = p.replace('.fx', '_Prepass.fx')
        newArea.effect.effectFilePath = p
    return newArea



def CopyAreaForPrePassDecal(area):
    newArea = CopyArea(area)
    if ((newArea.effect is not None) and (type(newArea.effect) != trinity.Tr2ShaderMaterial)):
        p = newArea.effect.effectFilePath.replace('/Exterior/', '/Interior/')
        if not p.endswith('_Prepass.fx'):
            p = p.replace('.fx', '_Prepass.fx')
        newArea.effect.effectFilePath = p
    return newArea



def CopyHairShader(fx):
    newMaterial = trinity.Tr2ShaderMaterial()
    newMaterial.highLevelShaderName = 'Hair'
    if ('detailed' in fx.effectFilePath.lower()):
        newMaterial.defaultSituation = 'Detailed'
    if ('dxt5n' in fx.effectFilePath.lower()):
        newMaterial.defaultSituation = (newMaterial.defaultSituation + ' OPT_USE_DXT5N')
    CopyCommonAvatarMaterialParams(newMaterial, fx)
    param = CopyVector4Parameter(fx, 'HairParameters')
    if (param is not None):
        newMaterial.parameters['HairParameters'] = param
    param = CopyVector4Parameter(fx, 'HairSpecularFactors1')
    if (param is not None):
        newMaterial.parameters['HairSpecularFactors1'] = param
    param = CopyVector4Parameter(fx, 'HairSpecularColor1')
    if (param is not None):
        newMaterial.parameters['HairSpecularColor1'] = param
    param = CopyVector4Parameter(fx, 'HairSpecularFactors2')
    if (param is not None):
        newMaterial.parameters['HairSpecularFactors2'] = param
    param = CopyVector4Parameter(fx, 'HairSpecularColor2')
    if (param is not None):
        newMaterial.parameters['HairSpecularColor2'] = param
    param = CopyVector4Parameter(fx, 'TangentMapParameters')
    if (param is not None):
        newMaterial.parameters['TangentMapParameters'] = param
    param = CopyFloatParameter(fx, 'HairDiffuseBias')
    if (param is not None):
        newMaterial.parameters['HairDiffuseBias'] = param
    param = CopyResourceByName(fx, 'TangentSampler')
    if (param is not None):
        newMaterial.parameters['TangentSampler'] = param
    return newMaterial



def CopyAreaForPrePassHair(area):
    newArea = CopyArea(area)
    fx = newArea.effect
    if ((fx is not None) and (hasattr(fx, 'effectFilePath') and ('hair' in fx.effectFilePath.lower()))):
        newMaterial = CopyHairShader(fx)
        newArea.effect = newMaterial
        newArea.useSHLighting = True
    return newArea



def GetHighLevelShaderByName(name):
    sm = trinity.GetShaderManager()
    for shader in sm.shaderLibrary:
        if (shader.name == name):
            return shader




def FindShaderMaterialParameter(mat, name):
    for param in mat.parameters:
        if (param.name == name):
            return param

    logStr = (name + ' target param not found in Tr2ShaderMaterial!')
    log.general.Log(logStr, log.LGERR)



def CopyCommonAvatarMaterialParams(mat, fx):
    param = CopyResourceByName(fx, 'DiffuseMap')
    if (param is not None):
        mat.parameters['DiffuseMap'] = param
    param = CopyResourceByName(fx, 'SpecularMap')
    if (param is not None):
        mat.parameters['SpecularMap'] = param
    param = CopyResourceByName(fx, 'NormalMap')
    if (param is not None):
        mat.parameters['NormalMap'] = param
    param = CopyResourceByName(fx, 'FresnelLookupMap')
    if (param is not None):
        mat.parameters['FresnelLookupMap'] = param
    param = CopyResourceByName(fx, 'CutMaskMap')
    if (param is not None):
        mat.parameters['CutMaskMap'] = param
    param = CopyResourceByName(fx, 'ColorNdotLLookupMap')
    if (param is not None):
        mat.parameters['ColorNdotLLookupMap'] = param
    param = CopyVector4Parameter(fx, 'MaterialDiffuseColor')
    if (param is None):
        param = trinity.Tr2Vector4Parameter()
        param.name = 'MaterialDiffuseColor'
        param.value = (1, 1, 1, 1)
    mat.parameters['MaterialDiffuseColor'] = param
    param = CopyVector4Parameter(fx, 'MaterialSpecularColor')
    if (param is not None):
        mat.parameters['MaterialSpecularColor'] = param
    param = CopyVector4Parameter(fx, 'MaterialSpecularCurve')
    if (param is not None):
        mat.parameters['MaterialSpecularCurve'] = param
    param = CopyVector4Parameter(fx, 'MaterialSpecularFactors')
    if (param is not None):
        mat.parameters['MaterialSpecularFactors'] = param
    param = CopyVector4Parameter(fx, 'FresnelFactors')
    if (param is not None):
        mat.parameters['FresnelFactors'] = param
    param = CopyVector4Parameter(fx, 'MaterialLibraryID')
    if (param is not None):
        mat.parameters['MaterialLibraryID'] = param
    param = CopyVector4Parameter(fx, 'TransformUV0')
    if (param is not None):
        mat.parameters['TransformUV0'] = param
    param = CopyFloatParameter(fx, 'CutMaskInfluence')
    if (param is not None):
        mat.parameters['CutMaskInfluence'] = param



def ConvertAreaToTr2ShaderMaterial(area, defaultSituation = None):
    area.effect = ConvertEffectToTr2ShaderMaterial(area.effect, defaultSituation)



def ConvertEffectToTr2ShaderMaterial(fx, defaultSituation = None):
    if hasattr(fx, 'effectFilePath'):
        fxpath = fx.effectFilePath.lower()
        newMaterial = trinity.Tr2ShaderMaterial()
        if (defaultSituation is not None):
            newMaterial.defaultSituation = defaultSituation
        if ('skinnedavatarbrdfdouble' in fxpath):
            newMaterial.highLevelShaderName = 'SkinnedAvatarBRDFDouble'
            CopyCommonAvatarMaterialParams(newMaterial, fx)
            param = CopyVector4Parameter(fx, 'Material2LibraryID')
            if (param is not None):
                newMaterial.parameters['Material2LibraryID'] = param
            param = CopyVector4Parameter(fx, 'Material2SpecularCurve')
            if (param is not None):
                newMaterial.parameters['Material2SpecularCurve'] = param
            param = CopyVector4Parameter(fx, 'Material2SpecularColor')
            if (param is not None):
                newMaterial.parameters['Material2SpecularColor'] = param
            param = CopyVector4Parameter(fx, 'Material2SpecularFactors')
            if (param is not None):
                newMaterial.parameters['Material2SpecularFactors'] = param
            return newMaterial
        if ('skinnedavatarbrdf' in fxpath):
            newMaterial.highLevelShaderName = 'SkinnedAvatarBrdf'
            CopyCommonAvatarMaterialParams(newMaterial, fx)
            return newMaterial
        if ('skinnedavatar' in fxpath):
            newMaterial.highLevelShaderName = 'SkinnedAvatar'
            CopyCommonAvatarMaterialParams(newMaterial, fx)
            return newMaterial
        if ('clothavatar' in fxpath):
            newMaterial.highLevelShaderName = 'ClothAvatar'
            CopyCommonAvatarMaterialParams(newMaterial, fx)
            return newMaterial
        return fx



def AddDepthNormalAreasToStandardMesh(mesh):
    mesh.depthNormalAreas.removeAt(-1)
    for area in mesh.opaqueAreas:
        newArea = CopyAreaForPrePassDepthNormal(area, SOURCE_AREA_TYPE_OPAQUE)
        if (newArea is not None):
            mesh.depthNormalAreas.append(newArea)
            newArea.effect.parameters['TransformUV0'].value = (0, 0, 1, 1)




def AddPrepassAreasToStandardMesh(mesh, processDepthAreas, processDepthNormalAreas):
    opaqueAreas = mesh.opaqueAreas
    if processDepthAreas:
        mesh.depthAreas.removeAt(-1)
    if processDepthNormalAreas:
        mesh.depthNormalAreas.removeAt(-1)
    mesh.decalPrepassAreas.removeAt(-1)
    mesh.opaquePrepassAreas.removeAt(-1)
    for area in mesh.transparentAreas:
        if (area.name[0:6] == 'Prepass_'):
            mesh.transparentAreas.remove(area)

    for area in opaqueAreas:
        if ((area.effect is not None) and (hasattr(area.effect, 'effectFilePath') and ('glass' in area.effect.effectFilePath.lower()))):
            newArea = CopyArea(area)
            if (newArea is not None):
                newArea.name = ('Prepass_' + newArea.name)
                mesh.transparentAreas.append(newArea)
            else:
                continue
        if processDepthNormalAreas:
            newArea = CopyAreaForPrePassDepthNormal(area, SOURCE_AREA_TYPE_OPAQUE)
            if (newArea is not None):
                mesh.depthNormalAreas.append(newArea)
        if processDepthAreas:
            newArea = CopyAreaForPrePassShadows(area, SOURCE_AREA_TYPE_OPAQUE)
            if (newArea is not None):
                mesh.depthAreas.append(newArea)
        newArea = CopyAreaForPrePassOpaque(area)
        if (newArea is not None):
            ConvertAreaToTr2ShaderMaterial(newArea, 'Prepass')
            mesh.opaquePrepassAreas.append(newArea)

    for area in mesh.decalAreas:
        if ((area.effect is not None) and (hasattr(area.effect, 'effectFilePath') and ('glass' in area.effect.effectFilePath.lower()))):
            newArea = CopyArea(area)
            if (newArea is not None):
                newArea.name = ('Prepass_' + newArea.name)
                mesh.transparentAreas.append(newArea)
            else:
                continue
        if processDepthNormalAreas:
            newArea = CopyAreaForPrePassDepthNormal(area, SOURCE_AREA_TYPE_DECAL)
            if (newArea is not None):
                mesh.depthNormalAreas.append(newArea)
        if processDepthAreas:
            newArea = CopyAreaForPrePassShadows(area, SOURCE_AREA_TYPE_DECAL)
            if (newArea is not None):
                mesh.depthAreas.append(newArea)
        newArea = CopyAreaForPrePassDecal(area)
        if (newArea is not None):
            ConvertAreaToTr2ShaderMaterial(newArea, 'Prepass')
            mesh.decalPrepassAreas.append(newArea)

    newAreas = []
    for area in mesh.transparentAreas:
        if ((area.effect is None) or ((not hasattr(area.effect, 'effectFilePath')) or ('glass' not in area.effect.effectFilePath.lower()))):
            newArea = CopyAreaForPrePassDecal(area)
            if (newArea is not None):
                ConvertAreaToTr2ShaderMaterial(newArea, 'SHLighting')
                newArea.useSHLighting = True
                newAreas.append(newArea)
                area.debugIsHidden = True

    mesh.transparentAreas.extend(newAreas)



def AddPrepassAreasToHair(mesh, processDepthAreas, processDepthNormalAreas):
    if processDepthAreas:
        mesh.depthAreas.removeAt(-1)
    if processDepthNormalAreas:
        mesh.depthNormalAreas.removeAt(-1)
    mesh.decalPrepassAreas.removeAt(-1)
    mesh.opaquePrepassAreas.removeAt(-1)
    if processDepthAreas:
        for area in mesh.decalAreas:
            newArea = CopyAreaForPrePassShadows(area, SOURCE_AREA_TYPE_DECAL)
            if (newArea is not None):
                mesh.depthAreas.append(newArea)

    for area in mesh.transparentAreas:
        if (area.name[0:6] == 'Decal_'):
            mesh.transparentAreas.remove(area)

    newAreas = []
    for area in mesh.transparentAreas:
        newArea = CopyAreaForPrePassHair(area)
        newArea.name = ('Decal_' + newArea.name)
        if (newArea is not None):
            newAreas.append(newArea)
        area.debugIsHidden = True

    mesh.transparentAreas.extend(newAreas)
    for area in mesh.decalAreas:
        newArea = CopyAreaForPrePassHair(area)
        newArea.name = ('Decal_' + newArea.name)
        if (newArea is not None):
            mesh.transparentAreas.append(newArea)
        area.debugIsHidden = True




def AddPrepassAreasToAvatar(avatar, visualModel, doll):
    createShadows = (doll.overrideLod <= pd.PerformanceOptions.shadowLod)
    collapseShadowMesh = (pd.PerformanceOptions.collapseShadowMesh and ((doll.overrideLod >= 0) and createShadows))
    collapseMainMesh = (pd.PerformanceOptions.collapseMainMesh and (doll.overrideLod == 2))
    collapsePLPMesh = (pd.PerformanceOptions.collapsePLPMesh and (doll.overrideLod >= 0))
    if collapseMainMesh:
        collapsePLPMesh = False
    plpMeshes = []
    if (collapseShadowMesh or (collapseMainMesh or collapsePLPMesh)):

        def FindSkinEffect(meshes):
            for mesh in meshes:
                fx = pd.GetEffectsFromMesh(mesh)
                for effect in fx:
                    if effect.name.lower().startswith('c_skin_'):
                        return effect




        sourceEffect = FindSkinEffect(visualModel.meshes)
        shadowEffect = pd.SkinLightmapRenderer.DuplicateEffect(sourceEffect, COLLAPSED_SHADOW_EFFECT_PATH)
        mods = doll.buildDataManager.GetSortedModifiers()
        file = blue.ResFile()
        UV = {}

        def FindTransformUV(meshes):
            for mesh in meshes:
                for areas in (mesh.opaqueAreas,
                 mesh.decalAreas,
                 mesh.transparentAreas):
                    for area in areas:
                        for p in area.effect.parameters:
                            if (p.name == 'TransformUV0'):
                                return p.value




            return (0, 0, 1, 1)


        for mod in mods:
            if ((mod.redfile is None) or (mod.redfile is '')):
                continue
            UV[mod.redfile] = FindTransformUV(mod.meshes)

        if collapseMainMesh:
            del visualModel.meshes[:]
        savedUV = {}
        for param in sourceEffect.parameters:
            if (param.name == 'TransformUV0'):
                savedUV[param.name] = param.value
                param.value = (0, 0, 1, 1)
                break

        for param in shadowEffect.parameters:
            if (param.name == 'TransformUV0'):
                param.value = (0, 0, 1, 1)
                break

        builder = trinity.Tr2SkinnedModelBuilder()
        builder.createGPUMesh = True
        builder.removeReversed = True
        builder.collapseToOpaque = True
        builder.enableSubsetBuilding = True
        builder.effectPath = COLLAPSED_SHADOW_EFFECT_PATH
        builder.SetAdjustPathMethod(lambda path: doll.AdjustGr2PathForLod(path))
        builder.enableVertexChopping = False
        builder.enableVertexPadding = False
        blends = {}
        for mod in mods:
            if ((mod.categorie in pd.BLENDSHAPE_CATEGORIES) and (mod.weight > 0)):
                blends[mod.name] = mod.weight
            red = mod.redfile
            if ((red is None) or (red is '')):
                continue
            if ('ragdoll' in red.lower()):
                continue
            peek = doll.AdjustRedFileForLod(red)
            if file.FileExists(peek):
                red = peek
            source = trinity.Tr2SkinnedModelBuilderSource()
            source.moduleResPath = red
            uv = UV.get(mod.redfile, (0, 0, 1, 1))
            source.upperLeftTexCoord = (uv[0], uv[1])
            source.lowerRightTexCoord = (uv[2], uv[3])
            builder.sourceMeshesInfo.append(source)

        for (name, weight,) in blends.iteritems():
            if (weight > 0.0):
                blend = trinity.Tr2SkinnedModelBuilderBlend()
                blend.name = name
                blend.power = weight
                builder.blendshapeInfo.append(blend)

        if not builder.PrepareForBuild():
            collapseShadowMesh = False
            collapseMainMesh = False
            collapsePLPMesh = False
        else:
            buildCount = 0
            while builder.Build():
                buildCount += 1

            if pd.PerformanceOptions.collapseVerbose:
                if ((buildCount > 1) and (doll.overrideLod == 2)):
                    log.LogWarn((('PD Collapse: lod2 has ' + str(buildCount)) + ' meshes after collapse (expected 1).'))
                if ((buildCount > 3) and (doll.overrideLod == 0)):
                    log.LogWarn((('PD Collapse: lod0 has ' + str(buildCount)) + ' meshes after collapse (expected 3 at most).'))
            model = builder.GetSkinnedModel()

            def TransferArrayOf(destEffect, sourceEffect):
                for p in sourceEffect.parameters:
                    if p.name.startswith('ArrayOf'):
                        for q in destEffect.parameters:
                            if (p.name == q.name):
                                destEffect.parameters.remove(q)
                                break

                        destEffect.parameters.append(p)



            for (count, mesh,) in enumerate(model.meshes):
                mesh.name = (('collapsed' + str(buildCount)) + str(count))
                if (collapseMainMesh or collapsePLPMesh):
                    for area in iter(mesh.opaqueAreas):
                        if createShadows:
                            newArea = trinity.Tr2MeshArea()
                            newArea.index = area.index
                            newArea.count = area.count
                            newArea.effect = shadowEffect
                            TransferArrayOf(shadowEffect, area.effect)
                            mesh.depthAreas.append(newArea)
                        TransferArrayOf(sourceEffect, area.effect)
                        area.effect = sourceEffect

                    if collapsePLPMesh:
                        plpMeshes.append(mesh)
                elif createShadows:
                    pd.MoveAreas(mesh.opaqueAreas, mesh.depthAreas)
                    for area in mesh.depthAreas:
                        TransferArrayOf(shadowEffect, area.effect)
                        area.effect = shadowEffect

                visualModel.meshes.append(mesh)

        if not collapseMainMesh:
            for param in sourceEffect.parameters:
                if (param.name == 'TransformUV0'):
                    param.value = savedUV[param.name]

    visualModel.ResetAnimationBindings()
    for mesh in visualModel.meshes:
        if (mesh in plpMeshes):
            continue
        if (mesh.name[0:4] == 'hair'):
            AddPrepassAreasToHair(mesh, processDepthAreas=(createShadows and (not collapseShadowMesh)), processDepthNormalAreas=(not collapsePLPMesh))
        else:
            AddPrepassAreasToStandardMesh(mesh, processDepthAreas=(createShadows and (not collapseShadowMesh)), processDepthNormalAreas=(not collapsePLPMesh))

    for mesh in plpMeshes:
        AddDepthNormalAreasToStandardMesh(mesh)
        mesh.opaqueAreas.removeAt(-1)

    if (doll.overrideLod == 2):
        for mesh in visualModel.meshes:
            for dn in mesh.depthNormalAreas:
                dn.effect.defaultSituation = (dn.effect.defaultSituation + ' OPT_USE_OBJECT_NORMAL')


    if (collapseMainMesh or collapsePLPMesh):
        for mesh in visualModel.meshes:
            for dn in mesh.depthNormalAreas:
                dn.effect.defaultSituation = (dn.effect.defaultSituation + ' OPT_COLLAPSED_PLP')


    if doll.useDXT5N:
        for mesh in visualModel.meshes:
            for areas in pd.MeshAreaListIterator(mesh, includePLP=True):
                for area in areas:
                    if hasattr(area.effect, 'defaultSituation'):
                        area.effect.defaultSituation = (area.effect.defaultSituation + ' OPT_USE_DXT5N')



    for mesh in visualModel.meshes:
        mesh.BindLowLevelShaders([])

    for mesh in avatar.clothMeshes:
        if (mesh.effect.name != ''):
            mesh.depthEffect = None
            newEffect = trinity.Tr2ShaderMaterial()
            newEffect.highLevelShaderName = 'Shadow'
            newEffect.defaultSituation = 'Cloth'
            newParam = CopyVector4Parameter(mesh.effect, 'TransformUV0')
            if (newParam is not None):
                newEffect.parameters['TransformUV0'] = newParam
            newParam = CopyVector4Parameter(mesh.effect, 'MaterialDiffuseColor')
            if (newParam is not None):
                newEffect.parameters['MaterialDiffuseColor'] = newParam
            newParam = CopyResourceByName(mesh.effect, 'DiffuseMap')
            if (newParam is not None):
                newEffect.parameters['DiffuseMap'] = newParam
            newParam = CopyResourceByName(mesh.effect, 'CutMaskMap')
            if (newParam is not None):
                newEffect.parameters['CutMaskMap'] = newParam
            newParam = CopyFloatParameter(mesh.effect, 'CutMaskInfluence')
            if (newParam is not None):
                newEffect.parameters['CutMaskInfluence'] = newParam
            mesh.depthEffect = newEffect
            newEffect.BindLowLevelShader([])
            mesh.depthNormalEffect = None
            if (hasattr(mesh.effect, 'effectFilePath') and (mesh.effect.effectFilePath.lower().find('hair') == -1)):
                newEffect = trinity.Tr2ShaderMaterial()
                newEffect.highLevelShaderName = 'NormalDepth'
                newEffect.defaultSituation = 'Cloth'
                if doll.useDXT5N:
                    newEffect.defaultSituation = (newEffect.defaultSituation + ' OPT_USE_DXT5N')
                newParam = CopyResourceByName(mesh.effect, 'NormalMap')
                if (newParam is not None):
                    newEffect.parameters['NormalMap'] = newParam
                newParam = CopyResourceByName(mesh.effect, 'SpecularMap')
                if (newParam is not None):
                    newEffect.parameters['SpecularMap'] = newParam
                newParam = CopyVector4Parameter(mesh.effect, 'TransformUV0')
                if (newParam is not None):
                    newEffect.parameters['TransformUV0'] = newParam
                newParam = CopyVector4Parameter(mesh.effect, 'MaterialSpecularCurve')
                if (newParam is not None):
                    newEffect.parameters['MaterialSpecularCurve'] = newParam
                newParam = CopyVector4Parameter(mesh.effect, 'MaterialLibraryID')
                if (newParam is None):
                    newParam = trinity.TriVector4Parameter()
                    newParam.name = 'MaterialLibraryID'
                    newParam.value = (11, 0, 0, 0)
                newEffect.parameters['MaterialLibraryID'] = newParam
                newParam = CopyVector4Parameter(mesh.effect, 'MaterialDiffuseColor')
                if (newParam is not None):
                    newEffect.parameters['MaterialDiffuseColor'] = newParam
                newParam = CopyResourceByName(mesh.effect, 'DiffuseMap')
                if (newParam is not None):
                    newEffect.parameters['DiffuseMap'] = newParam
                newParam = CopyResourceByName(mesh.effect, 'CutMaskMap')
                if (newParam is not None):
                    newEffect.parameters['CutMaskMap'] = newParam
                newParam = CopyFloatParameter(mesh.effect, 'CutMaskInfluence')
                if (newParam is not None):
                    newEffect.parameters['CutMaskInfluence'] = newParam
                mesh.depthNormalEffect = newEffect
                newEffect.BindLowLevelShader([])
            if hasattr(mesh.effect, 'effectFilePath'):
                if (mesh.effect.effectFilePath.lower().find('hair') != -1):
                    newMaterial = CopyHairShader(mesh.effect)
                    newMaterial.name = mesh.effect.name
                    newMaterial.defaultSituation = (newMaterial.defaultSituation + ' Cloth')
                    if doll.useDXT5N:
                        newMaterial.defaultSituation = (newMaterial.defaultSituation + ' OPT_USE_DXT5N')
                    newMaterial.BindLowLevelShader([])
                    mesh.effect = newMaterial
                    mesh.useTransparentBatches = True
                    mesh.useSHLighting = True
                    if (hasattr(mesh.effectReversed, 'effectFilePath') and (mesh.effectReversed.effectFilePath.lower().find('hair') != -1)):
                        newMaterial = CopyHairShader(mesh.effectReversed)
                        newMaterial.name = mesh.effectReversed.name
                        newMaterial.defaultSituation = (newMaterial.defaultSituation + ' Cloth')
                        if doll.useDXT5N:
                            newMaterial.defaultSituation = (newMaterial.defaultSituation + ' OPT_USE_DXT5N')
                        newMaterial.BindLowLevelShader([])
                        mesh.effectReversed = newMaterial
                        mesh.useTransparentBatches = True
                        mesh.useSHLighting = True
                else:
                    situation = 'Prepass Cloth'
                    if doll.useDXT5N:
                        situation = (situation + ' OPT_USE_DXT5N')
                    newMaterial = ConvertEffectToTr2ShaderMaterial(mesh.effect, situation)
                    newMaterial.name = mesh.effect.name
                    newMaterial.BindLowLevelShader([])
                    mesh.effect = newMaterial
                    mesh.useTransparentBatches = True
                    if (hasattr(mesh.effectReversed, 'effectFilePath') and (mesh.effectReversed.effectFilePath.lower().find('hair') == -1)):
                        newMaterial = ConvertEffectToTr2ShaderMaterial(mesh.effectReversed, situation)
                        newMaterial.name = mesh.effectReversed.name
                        newMaterial.BindLowLevelShader([])
                        mesh.effectReversed = newMaterial
                        mesh.useTransparentBatches = True



exports = {'paperDoll.prePassFixup.AddPrepassAreasToAvatar': AddPrepassAreasToAvatar}

